package no.hib.mod250.chat.client.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Widget;

public class Util {

	public static class Hash {

		public static String convertToHex(byte[] data) {
			StringBuffer buf = new StringBuffer();
			for (int i = 0; i < data.length; i++) {
				int halfbyte = (data[i] >>> 4) & 0x0F;
				int two_halfs = 0;
				do {
					if ((0 <= halfbyte) && (halfbyte <= 9))
						buf.append((char) ('0' + halfbyte));
					else
						buf.append((char) ('a' + (halfbyte - 10)));
					halfbyte = data[i] & 0x0F;
				} while (two_halfs++ < 1);
			}
			return buf.toString();
		}

		private static String mdInstance(String text, String instance) {
			MessageDigest md = null;
			try {
				md = MessageDigest.getInstance(instance);
			} catch (NoSuchAlgorithmException e) {
				return null;
			}

			byte[] sha1hash = new byte[40];
			md.update(text.getBytes());
			sha1hash = md.digest();
			return convertToHex(sha1hash);
		}

		public static String SHA1(String text) {
			return mdInstance(text, "SHA-1");
		}

		public static String MD5(String text) {
			return mdInstance(text, "MD5");
		}

	}

	public static class Gravatar {

		private static String GRAVATAR_URL = "http://www.gravatar.com/avatar/{0}?d=mm&s={1}";

		public static Image generate(String email, int size) {
			if (email == null) {
				return null;
			}

			String emailMD5 = Util.Hash.MD5(email);
			return new Image(GRAVATAR_URL.replace("{0}", emailMD5).replace(
					"{1}", "" + size));
		}

	}

	/**
	 * @param s
	 *            String to parse for URL's: http://X and www.X
	 * @return JavaScript array which contains URL's
	 */
	public static native JavaScriptObject parseURLs(String s) /*-{
		var expression = "((www\\.|((ht|f)tp(s?))\\:\\/\\/){1}\\S+)";
		var regularExpression = new RegExp(expression, "gi");

		var match = null;
		var uris = [];
		while (match = regularExpression.exec(s))
		{
		uris.push(match[1]);
		}

		return uris;
	}-*/;

	public static class URI {

		public static class MediaParser {

			// VARIABLES

			// ... OPERATORS

			public static int VIDEO_YOUTUBE = 0x1;
			public static int VIDEO_GOOGLE = 0x2;
			public static int VIDEO_ALL = VIDEO_YOUTUBE | VIDEO_GOOGLE;

			public static int IMAGE_JPG = 0x10;
			public static int IMAGE_GIF = 0x20;
			public static int IMAGE_PNG = 0x40;
			public static int IMAGE_ALL = IMAGE_JPG | IMAGE_GIF | IMAGE_PNG;

			public static int ANCHOR = 0x100;

			public static int ALL = IMAGE_ALL | VIDEO_ALL;

			// ... /OPERATORS

			private static String EMBED_YOUTUBE_WSIZE = "<object width=\"{width}\" height=\"{height}\">"
					+ "<param name=\"movie\" value=\"http://www.youtube.com/v/{id}\"></param>"
					+ "<param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param>"
					+ "<embed src=\"http://www.youtube.com/v/{id}\" type=\"application/x-shockwave-flash\" allowscriptaccess=\"always\" allowfullscreen=\"true\" width=\"{width}\" height=\"{height}\"></embed>"
					+ "</object>";

			private static String EMBED_YOUTUBE = "<object>"
					+ "<param name=\"movie\" value=\"http://www.youtube.com/v/{id}?showsearch=0&rel=0\"></param>"
					+ "<param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param>"
					+ "<embed src=\"http://www.youtube.com/v/{id}?showsearch=0&rel=0\" type=\"application/x-shockwave-flash\" allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed>"
					+ "</object>";

			private static String EMBED_GOOGLEVIDEO_WSIZE = "<embed id=VideoPlayback "
					+ "src=http://video.google.com/googleplayer.swf?docid=4241480654150026320&hl=en&fs=true "
					+ "style=width:400px;height:326px allowFullScreen=true allowScriptAccess=always "
					+ "type=application/x-shockwave-flash> </embed>";

			private static String EMBED_GOOGLEVIDEO = "<embed id=VideoPlayback "
					+ "src=http://video.google.com/googleplayer.swf?docid={id} "
					+ "allowFullScreen=true allowScriptAccess=always "
					+ "type=application/x-shockwave-flash> </embed>";

			private static String CONTAIN_YOUTUBE = "youtube.com";
			private static String CONTAIN_GOOGLEVIDEO = "video.google";
			private static String CONTAIN_JPG = "jpg", CONTAIN_JPEG = "jpeg",
					CONTAIN_PNG = "png", CONTAIN_GIF = "gif";

			// /VARIABLES

			// FUNCTIONS

			public static List<Widget> parse(String text) {
				return parse(text, ALL);
			}

			public static List<Widget> parse(String text, int acceptOperator) {
				List<Widget> widgets = new ArrayList<Widget>();

				// Parse text into URLs
				JavaScriptObject jsURLs = Util.parseURLs(text);
				String[] urls = jsURLs.toString().split(",");

				Widget widget = new Widget();
				for (String url : urls) {
					// Pad "http" in front of non "http" urls
					if (!url.toLowerCase().startsWith("http")) {
						url = "http://" + url;
					}

					// Image
					if (isImage(url, acceptOperator)) {
						widget = getImage(url);
					}
					// Video
					else if (isVideo(url, acceptOperator)) {
						widget = getVideo(url);
					}
					// Anchor
					else if ((acceptOperator & ANCHOR) >= 0) {
						widget = new Anchor(Util.URI.host(url), url);
						((Anchor) widget).setTarget("_blank");
					}

					widgets.add(widget);
				}

				return widgets;
			}

			// ... GET WIDGET

			private static HTML getVideo(String url) {
				String host = Util.URI.host(url).toLowerCase();

				// Youtube
				if (host.contains(CONTAIN_YOUTUBE)) {
					String youtubeId = getYoutubeId(url);

					if (youtubeId == null || youtubeId == "") {
						return new HTML("Illegal youtube id");
					}

					return new HTML(EMBED_YOUTUBE.replace("{id}", youtubeId));
				}
				// Google video
				else if (host.contains(CONTAIN_GOOGLEVIDEO)) {
					String googlevideoId = getGoogleVideoId(url);

					if (googlevideoId == null || googlevideoId == "") {
						return new HTML("Illegal google video id");
					}

					return new HTML(EMBED_GOOGLEVIDEO.replace("{id}",
							googlevideoId));
				}

				return new HTML("error");
			}

			private static Image getImage(final String url) {
				Image image = new Image(url);
				image.addClickHandler(new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						Window.open(url, null, null);
					}
				});
				return image;
			}

			// ... /GET WIDGET

			// ... IS MEDIA

			private static boolean isImage(String url, int acceptOperator) {
				String path = Util.URI.path(url);

				if (path == null) {
					return false;
				}

				String type = path.substring(path.lastIndexOf(".") + 1)
						.toLowerCase();

				if ((type.equalsIgnoreCase(CONTAIN_JPG) || type
						.equalsIgnoreCase(CONTAIN_JPEG))
						&& (acceptOperator & IMAGE_JPG) >= 0) {
					return true;
				} else if (type.equalsIgnoreCase(CONTAIN_PNG)
						&& (acceptOperator & IMAGE_PNG) >= 0) {
					return true;
				} else if (type.equalsIgnoreCase(CONTAIN_GIF)
						&& (acceptOperator & IMAGE_GIF) >= 0) {
					return true;
				}

				return false;
			}

			private static boolean isVideo(String host, int acceptOperator) {
				if (host.toLowerCase().contains(CONTAIN_YOUTUBE)
						&& (acceptOperator & VIDEO_YOUTUBE) >= 0) {
					return true;
				} else if (host.toLowerCase().contains(CONTAIN_GOOGLEVIDEO)
						&& (acceptOperator & VIDEO_GOOGLE) >= 0) {
					return true;
				}

				return false;
			}

			// ... /IS MEDIA

			// ... JSNI

			private static native String getYoutubeId(String url) /*-{
				var re = new RegExp(/[\\?\\&]v=([^\\?\\&]+)/);
				var m = null;
				if (url && (m = re.exec(url))) {
					return m[1];
				}
				return "";
			}-*/;

			private static native String getGoogleVideoId(String url) /*-{
				var re = new RegExp(/[\\?\\&]docid=([^\\?\\&\\#]+)/);
				var m;
				if (url && (m = re.exec(url))) {
					return m[1];
				}
				return "";
			}-*/;

			// ... /JSNI

			// /FUNCTIONS

		}

		public static class LinkParser {

			// VARIABLES

			// /VARIABLES

			// CONSTRUCTOR

			public static Map<String, Anchor> parse(String text) {
				Map<String, Anchor> anchors = new HashMap<String, Anchor>();

				// Parse text into URLs
				JavaScriptObject jsURLs = Util.parseURLs(text);

				if (jsURLs.toString() == "Unknown") {

					String[] urls = jsURLs.toString().split(",");

					Anchor anchor = null;
					for (String url : urls) {

						if (url != null && url != "" && url != "\n") {
							// Pad "http" in front of non "http" urls
							String urlNew = url;
							if (!url.toLowerCase().startsWith("http")) {
								urlNew = "http://" + url;
							}

							anchor = new Anchor();

							// Set anchor href
							anchor.setHref(urlNew);

							// Set anchor text
							anchor.setText(urlText(urlNew));
							anchor.setTarget("_blank");

							// Add anchor
							anchors.put(url, anchor);

						}
					}

				}

				return anchors;
			}

			// /CONSTRUCTOR

			// FUNCTIONS

			private static String urlText(String url) {
				String text = "";
				String host = Util.URI.host(url);
				String path = Util.URI.path(url);

				text += host;

				if (path != null) {
					int tmpI = url.indexOf(host) + host.length();

					String tmp = tmpI >= 0 ? url.substring(tmpI) : "";
					if (tmp.length() > 10) {
						text += "/..." + url.substring(url.length() - 10);
					} else {
						text += tmp;
					}
				}

				return text;
			}

			// /FUNCTIONS

		}

		public static native String host(String uri) /*-{
			var re = new RegExp("(?:([-+a-z0-9]+)://" + // Scheme
			"((.[^:]*):?(.*)?@)?" + // Userinfo
			"(.[^:/]*)"           + // Host
			":?([0-9]{1,6})?)?"   + // Port
			"([/.].[^?#]*)?"      + // Path
			"([?](.[^#]*))?"      + // Query
			"#?(.*)?", "i");        // Fragment

			var m;
			if (uri && (m = re.exec(uri))) {
			scheme   = m[1] && m[1].toLowerCase();
			username = m[3];
			password = m[4];
			host     = m[5] && m[5].toLowerCase();
			port     = m[6] && parseInt(m[6],10);
			path     = m[7];
			query    = m[9];
			fragment = m[10];



			return host;
			}
			else
			{
			return "";
			}
		}-*/;

		public static native String path(String uri) /*-{
			//var uri = new $wnd.URI(uri);
			//return uri.path;
			//return $wnd.sayHello(uri);

			var re = new RegExp("(?:([-+a-z0-9]+)://" + // Scheme
			"((.[^:]*):?(.*)?@)?" + // Userinfo
			"(.[^:/]*)"           + // Host
			":?([0-9]{1,6})?)?"   + // Port
			"([/.].[^?#]*)?"      + // Path
			"([?](.[^#]*))?"      + // Query
			"#?(.*)?", "i");        // Fragment

			var m;
			if (uri && (m = re.exec(uri))) {
			scheme   = m[1] && m[1].toLowerCase();
			username = m[3];
			password = m[4];
			host     = m[5] && m[5].toLowerCase();
			port     = m[6] && parseInt(m[6],10);
			path     = m[7];
			query    = m[9];
			fragment = m[10];

			return path;
			}
			else
			{
			return "";
			}
		}-*/;

	}

}
